home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / migrate / mig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-13  |  11.0 KB  |  461 lines

  1. /* 
  2.  * mig.c --
  3.  *
  4.  *    Program to perform remote execution using process migration.
  5.  *
  6.  * Copyright 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/migrate/RCS/mig.c,v 1.14 90/09/24 14:38:37 douglis Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20.  
  21. #include <sprite.h>
  22. #include <status.h>
  23. #include <option.h>
  24. #include <proc.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <host.h>
  28. #include <sys/wait.h>
  29. #include <signal.h>
  30. #include <string.h>
  31. #include <errno.h>
  32. #include <mig.h>
  33.  
  34. /*
  35.  * Library imports:
  36.  */
  37.  
  38. extern char **environ;
  39.  
  40. /*
  41.  * Forward declarations
  42.  */
  43. static void DoExec();
  44. static int RemotePathExec();
  45.  
  46. int debug = 0;
  47. char *host = NULL;
  48. int hostID = -1;
  49. char *procIDString = NULL;
  50. int local = 0;
  51. int background = 0;
  52. int backPrio = 0;
  53. int verbose = 0;
  54. char *execName = NULL;
  55.  
  56. Option optionArray[] = {
  57.     {OPT_STRING, "h", (Address) &host,
  58.      "String identifier for host to migrate onto (default is random selection)."},
  59.     {OPT_INT, "H", (Address) &hostID,
  60.      "Numeric identifier for host to migrate onto."},
  61.     {OPT_TRUE, "b", (Address) &background,
  62.      "Execute command in background and print processID."},
  63.     {OPT_TRUE, "B", (Address) &backPrio,
  64.      "Execute command at background priority."},
  65.     {OPT_TRUE, "l", (Address) &local,
  66.      "Execute command locally if no idle node is available."},
  67.     {OPT_TRUE, "D", (Address) &debug,
  68.      "Enable debugging messages."},
  69.     {OPT_STRING, "E", (Address) &execName,
  70.      "Exec the command specified by this argument, setting argv[0] to the first argument following the option list."},
  71.     {OPT_TRUE, "v", (Address) &verbose,
  72.      "Print useful information, such as which host is selected."},
  73.     {OPT_STRING, "p", (Address) &procIDString,
  74.      "Process ID of process to migrate (default is to start shell, or issue command given as remaining arguments)"},
  75. };
  76.  
  77. /*
  78.  * Default shell to invoke if none found in environment.
  79.  */
  80. #define SHELL "csh"
  81.  
  82. main(argc, argv)
  83.     int  argc;
  84.     char *argv[];
  85. {
  86.     ReturnStatus status;
  87.     char *myName;
  88.     char **argArray;
  89.     char *shell;
  90.     int pid;
  91.     Host_Entry *hostPtr;
  92.     int i;
  93.     int selectedHost;
  94.     int doCmd;
  95.     int procID;
  96.     int flags;
  97.     
  98.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray), 
  99.              OPT_ALLOW_CLUSTERING|OPT_OPTIONS_FIRST);
  100.  
  101.     myName = argv[0];
  102.     if (hostID != -1 && host != (char *) NULL) {
  103.     fprintf(stderr, "%s: -h and -H options are mutually exclusive\n",
  104.         myName);
  105.     exit(1);
  106.     }
  107.     if (debug) {
  108.     verbose = 1;
  109.     }
  110.     if (procIDString != (char *) NULL) {
  111.     if (background) {
  112.         fprintf(stderr, "%s: -b and -p options are mutually exclusive\n",
  113.             myName);
  114.         exit(1);
  115.     }
  116.     procID = strtol(procIDString, (char **) NULL, 16);
  117.     if (procID <= 0) {
  118.         (void)fprintf(stderr, "%s: invalid process ID: %s.\n", myName,
  119.               procIDString);
  120.         exit(1);
  121.     }
  122.     doCmd = 0;
  123.     if (argc > 1) {
  124.         (void)fprintf(stderr, "%s: extra arguments ignored.\n", myName);
  125.     }
  126.     if (local) {
  127.         (void)fprintf(stderr,
  128.               "%s: -l argument ignored when migrating process.\n",
  129.               myName);
  130.         local = 0;
  131.     }
  132.     flags = MIG_PROC_AGENT;
  133.     } else {
  134.     doCmd = 1;
  135.     procID = PROC_MY_PID;
  136.     if (argc == 1) {
  137.         argArray = (char **) malloc(2 * sizeof(char *));
  138.         shell = getenv("SHELL");
  139.         if (shell == (char *) NULL) {
  140.         shell = SHELL;
  141.         }
  142.         argArray[0] = shell;
  143.             execName = shell;
  144.         argArray[1] = NULL;
  145.     } else {
  146.         argArray = &argv[1];
  147.         if (!execName) {
  148.         execName = argArray[0];
  149.         }
  150.     }
  151.     flags = background ? MIG_PROC_AGENT : 0;
  152.     }  
  153.     if (host != (char *) NULL) {
  154.     selectedHost = 0;
  155.     hostPtr = Host_ByName(host);
  156.     if (hostPtr == (Host_Entry *) NULL) {
  157.         fprintf(stderr, "%s: %s: no such host.\n", myName, host);
  158.         exit(1);
  159.     }
  160.     hostID = hostPtr->id;
  161.     Host_End();
  162.     } else if (hostID != -1) {
  163.     selectedHost = 0;
  164.     } else {
  165.     int hostNumbers[1];
  166.     int hostsAssigned;
  167.     
  168.     selectedHost = 1;
  169.     (void) signal(SIGINT, SIG_IGN);
  170.     hostsAssigned = Mig_RequestIdleHosts(1, backPrio ?
  171.                          MIG_LOW_PRIORITY :
  172.                          MIG_NORMAL_PRIORITY,
  173.                          flags,
  174.                          (void (*)()) NULL, hostNumbers);
  175.     if (hostsAssigned < 0) {
  176.         perror("Mig_RequestIdleHosts");
  177.         exit(1);
  178.     }
  179.     if (hostsAssigned == 0) {
  180.         if (!local) {
  181.         fprintf(stderr, "%s: no idle host available.\n", myName);
  182.         exit(1);
  183.         }
  184.         hostID = 0;
  185.     } else {
  186.         hostID = hostNumbers[0];
  187.     }
  188.     if (verbose) {
  189.         if (hostID) {
  190.         hostPtr = Host_ByID(hostID);
  191.         if (hostPtr == (Host_Entry *) NULL) {
  192.             fprintf(stderr, "%s: unable to find host %d.\n",
  193.                 myName, hostID);
  194.             exit(1);
  195.         }
  196.         fprintf(stderr, "%s: migrating to host %s.\n", myName,
  197.             hostPtr->name);
  198.         Host_End();
  199.         } else {
  200.         fprintf(stderr,
  201.             "%s: no idle host available; running locally.\n",
  202.             myName);
  203.         }
  204.     }
  205.     }
  206.  
  207.     if ((selectedHost || background) && hostID && doCmd) {
  208.     /*
  209.      * Wait for the process to complete so we can register that we're
  210.      * through with the host.
  211.      */
  212.     pid = fork();
  213.     if (pid < 0) {
  214.         perror("Error forking child");
  215.         exit(1);
  216.     }
  217.         
  218.     if (pid) {
  219.         union wait status;
  220.         int error;
  221.         int exited = 0;
  222.         int exitCode;
  223.  
  224.  
  225.         if (background) {
  226.         printf("%x\n", pid);
  227.         exit(0);
  228.         }
  229.         do {
  230.         
  231.         error = wait(&status);
  232.         if (error == -1) {
  233.             perror("wait");
  234.             exit(1);
  235.         } else if (error != pid && debug) {
  236.             (void) fprintf(stderr, "%s: received status %d from wait.\n",
  237.                    myName, error);
  238.         } else if (error == pid) {
  239.             if (status.w_stopval != WSTOPPED) {
  240.             exited = 1;
  241.             if (status.w_termsig != 0) {
  242.                 if (debug) {
  243.                 (void) fprintf(stderr,
  244.                            "%s: process was signalled.\n",
  245.                            myName);
  246.                 }
  247.                 exitCode = status.w_termsig;
  248.             } else {
  249.                 exitCode = status.w_retcode;
  250.             }
  251.             } else {
  252.             if (debug) {
  253.                 (void) fprintf(stderr,
  254.                        "%s: process was suspended.\n",
  255.                        myName);
  256.             }
  257.             }
  258.         }
  259.         } while (!exited);
  260. #ifdef undef
  261.         if (debug) {
  262.         (void) fprintf(stderr,
  263.                    "%s: Exited(%d).  Calling Mig_Done(%d).\n",
  264.                    myName, exitCode, hostID);
  265.         (void) fflush(stderr);
  266.         }
  267.         (void) Mig_Done(hostID);
  268. #endif
  269.         exit(exitCode);
  270.     } else {
  271.         (void) signal(SIGINT, SIG_DFL);
  272.     }
  273.     }
  274.     if (hostID && !doCmd) {
  275.     /*
  276.      * We're migrating someone else.
  277.      */
  278.     
  279.     if (debug) {
  280.         (void) fprintf(stderr, "Calling Proc_Migrate(%d, %d).\n", procID,
  281.                hostID);
  282.         (void) fflush(stderr);
  283.     }
  284.     
  285.     status = Proc_Migrate(procID, hostID);
  286.     if (status != SUCCESS) {
  287.         fprintf(stderr, "%s: error in Proc_Migrate: %s\n",
  288.             myName, Stat_GetMsg(status));
  289.         fflush(stderr);
  290.         if (!local) {
  291.         exit(1);
  292.         }
  293.     }
  294.     }
  295.     if (!doCmd) {
  296.     exit(0);
  297.     }
  298.     /*
  299.      * Still the child here, or the only process if we were running locally
  300.      * and never forked.
  301.      */
  302.     if (debug) {
  303.     (void) fprintf(stderr, "Calling RemotePathExec(%s,...,%d).\n",
  304.                execName, hostID);
  305.     (void) fflush(stderr);
  306.     }
  307.     status = RemotePathExec(execName, argArray, hostID);
  308.     perror("Error execing program");
  309.     exit(status);
  310. }
  311.  
  312.  
  313. /*
  314.  *-----------------------------------------------------------------------
  315.  *
  316.  * DoExec --
  317.  *
  318.  *    Function to actually execute a program. If the exec didn't succeed
  319.  *    because the file isn't in a.out format, attempt to execute
  320.  *    it as a bourne shell script.
  321.  *
  322.  * Results:
  323.  *    None.  Doesn't even return unless the exec failed.
  324.  *
  325.  * Side Effects:
  326.  *    A program may be execed over this one.
  327.  *
  328.  *-----------------------------------------------------------------------
  329.  */
  330.  
  331. static void
  332. DoExec(file, argv, hostID)
  333.     char *file;            /* File to execute. */
  334.     char **argv;        /* Arguments to the program. */
  335.     int hostID;            /* ID of host on which to exec */
  336. {
  337.     ReturnStatus status;
  338.     status = Proc_RemoteExec(file, argv, environ, hostID);
  339.     if (debug) {
  340.     fprintf(stderr, "Proc_RemoteExec(\"%s\"): %s\n", file,
  341.         Stat_GetMsg(status));
  342.     }
  343.     errno = Compat_MapCode(status);
  344.     if (errno == ENOEXEC) {
  345.     /*
  346.      * Attempt to execute the file as a shell script using
  347.      * the Bourne shell)
  348.      */
  349.     register char **newargv;
  350.     register int i;
  351.  
  352.     for (i = 0; argv[i] != 0; i++) {
  353.         /* Empty loop body */
  354.     }
  355.     newargv = (char **) malloc((unsigned) ((i+1)*sizeof (char *)));
  356.     newargv[0] = "sh";
  357.     newargv[1] = file;
  358.     for (i = 1; argv[i] != 0; i++) {
  359.         newargv[i+1] = argv[i];
  360.     }
  361.     newargv[i+1] = 0;
  362.     status = Proc_RemoteExec("/sprite/cmds/sh", newargv, environ, hostID);
  363.     errno = Compat_MapCode(status);
  364.     }
  365. }
  366.  
  367. /*
  368.  *----------------------------------------------------------------------
  369.  *
  370.  * RemotePathExec --
  371.  *
  372.  *    Execute a process, using the current environment variable,
  373.  *    instead of an explicitly-supplied one.  Also, imitate the
  374.  *    shell's actions in trying each directory in a search path
  375.  *    (given by the "PATH" environment variable).  Also, specify
  376.  *    a remote host.  This is taken from the library execve call.
  377.  *
  378.  * Results:
  379.  *    This procedure returns only if the exec fails.  In this case
  380.  *    the return value is -1.
  381.  *
  382.  * Side effects:
  383.  *    Overlays the current process with a new image.  See the man
  384.  *    page for details.
  385.  *
  386.  *----------------------------------------------------------------------
  387.  */
  388.  
  389. static int
  390. RemotePathExec(name, argv, hostID)
  391.     char *name;            /* Name of file containing program to exec. */
  392.     char **argv;        /* Array of arguments to pass to program. */
  393.     int hostID;            /* ID of host on which to exec */
  394. {
  395.     char *path;
  396.     char *fullName;
  397.     register char *first, *last;
  398.     int size, noAccess;
  399.  
  400.     noAccess = 0;
  401.  
  402.     if (index(name, '/') != 0) {
  403.     /*
  404.      * If the name specifies a path, don't search for it on the search path,
  405.      * just try and execute it.
  406.      */
  407.     DoExec(name, argv, hostID);
  408.     return -1;
  409.     }
  410.  
  411.     path = getenv("PATH");
  412.     if (path == 0) {
  413.     path = "/sprite/cmds";
  414.     }
  415.     fullName = malloc((unsigned) (strlen(name) + strlen(path)) + 2);
  416.     for (first = path; ; first = last+1) {
  417.  
  418.     /*
  419.      * Generate the next file name to try.
  420.      */
  421.  
  422.     for (last = first; (*last != 0) && (*last != ':'); last++) {
  423.         /* Empty loop body. */
  424.     }
  425.     size = last-first;
  426.     (void) strncpy(fullName, first, size);
  427.     if (last[-1] != '/') {
  428.         fullName[size] = '/';
  429.         size++;
  430.     }
  431.     (void) strcpy(fullName + size, name);
  432.  
  433.     if (debug) {
  434.         fprintf(stderr, "Trying DoExec(\"%s\")....\n", fullName);
  435.     }
  436.     DoExec(fullName, argv, hostID);
  437.     if (debug) {
  438.         fprintf(stderr, "DoExec(\"%s\") => %d.\n", fullName, errno);
  439.     }
  440.     if (errno == EACCES) {
  441.         noAccess = 1;
  442.     } else if (errno != ENOENT) {
  443.         break;
  444.     }
  445.     if (*last == 0) {
  446.         /*
  447.          * Hit the end of the path. We're done.
  448.          * If there existed a file by the right name along the search path,
  449.          * but its permissions were wrong, return FS_NO_ACCESS. Else return
  450.          * whatever we just got back.
  451.          */
  452.         if (noAccess) {
  453.         errno = EACCES;
  454.         }
  455.         break;
  456.     }
  457.     }
  458.     free((char *) fullName);
  459.     return -1;
  460. }
  461.